home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2005 March / Macworld CD March 2005 - Marathon Trilogy.iso / Shareware World / iPod / iPodderX.sit / iPodderX / iPodderX.app / Contents / Resources / Storage.py < prev    next >
Encoding:
Python Source  |  2005-01-07  |  4.9 KB  |  171 lines

  1. # Written by Bram Cohen
  2. # see LICENSE.txt for license information
  3.  
  4. from sha import sha
  5. from bisect import bisect_right
  6.  
  7. class Storage:
  8.     def __init__(self, files, open, exists, getsize):
  9.         # can raise IOError and ValueError
  10.         self.ranges = []
  11.         total = 0l
  12.         so_far = 0l
  13.         for file, length in files:
  14.             if length != 0:
  15.                 self.ranges.append((total, total + length, file))
  16.                 total += length
  17.                 if exists(file):
  18.                     l = getsize(file)
  19.                     if l > length:
  20.                         l = length
  21.                     so_far += l
  22.             elif not exists(file):
  23.                 open(file, 'wb').close()
  24.         self.begins = [i[0] for i in self.ranges]
  25.         self.total_length = total
  26.         self.handles = {}
  27.         self.whandles = {}
  28.         self.tops = {}
  29.         for file, length in files:
  30.             if exists(file):
  31.                 l = getsize(file)
  32.                 if l != length:
  33.                     self.handles[file] = open(file, 'rb+')
  34.                     self.whandles[file] = 1
  35.                     if l > length:
  36.                         self.handles[file].truncate(length)
  37.                 else:
  38.                     self.handles[file] = open(file, 'rb')
  39.                 self.tops[file] = l
  40.             else:
  41.                 self.handles[file] = open(file, 'wb+')
  42.                 self.whandles[file] = 1
  43.  
  44.     def was_preallocated(self, pos, length):
  45.         for file, begin, end in self._intervals(pos, length):
  46.             if self.tops.get(file, 0) < end:
  47.                 return False
  48.         return True
  49.  
  50.     def set_readonly(self):
  51.         # may raise IOError or OSError
  52.         for file in self.whandles.keys():
  53.             old = self.handles[file]
  54.             old.flush()
  55.             old.close()
  56.             self.handles[file] = open(file, 'rb')
  57.  
  58.     def get_total_length(self):
  59.         return self.total_length
  60.  
  61.     def _intervals(self, pos, amount):
  62.         r = []
  63.         stop = pos + amount
  64.         p = bisect_right(self.begins, pos) - 1
  65.         while p < len(self.ranges) and self.ranges[p][0] < stop:
  66.             begin, end, file = self.ranges[p]
  67.             r.append((file, max(pos, begin) - begin, min(end, stop) - begin))
  68.             p += 1
  69.         return r
  70.  
  71.     def read(self, pos, amount):
  72.         r = []
  73.         for file, pos, end in self._intervals(pos, amount):
  74.             h = self.handles[file]
  75.             h.seek(pos)
  76.             r.append(h.read(end - pos))
  77.         return ''.join(r)
  78.  
  79.     def write(self, pos, s):
  80.         # might raise an IOError
  81.         total = 0
  82.         for file, begin, end in self._intervals(pos, len(s)):
  83.             if not self.whandles.has_key(file):
  84.                 self.handles[file].close()
  85.                 self.handles[file] = open(file, 'rb+')
  86.                 self.whandles[file] = 1
  87.             h = self.handles[file]
  88.             h.seek(begin)
  89.             h.write(s[total: total + end - begin])
  90.             total += end - begin
  91.  
  92.     def close(self):
  93.         for h in self.handles.values():
  94.             h.close()
  95.  
  96. def lrange(a, b, c):
  97.     r = []
  98.     while a < b:
  99.         r.append(a)
  100.         a += c
  101.     return r
  102.  
  103. # everything below is for testing
  104.  
  105. from fakeopen import FakeOpen
  106.  
  107. def test_Storage_simple():
  108.     f = FakeOpen()
  109.     m = Storage([('a', 5)], f.open, f.exists, f.getsize)
  110.     assert f.files.keys() == ['a']
  111.     m.write(0, 'abc')
  112.     assert m.read(0, 3) == 'abc'
  113.     m.write(2, 'abc')
  114.     assert m.read(2, 3) == 'abc'
  115.     m.write(1, 'abc')
  116.     assert m.read(0, 5) == 'aabcc'
  117.     
  118. def test_Storage_multiple():
  119.     f = FakeOpen()
  120.     m = Storage([('a', 5), ('2', 4), ('c', 3)], 
  121.         f.open, f.exists, f.getsize)
  122.     x = f.files.keys()
  123.     x.sort()
  124.     assert x == ['2', 'a', 'c']
  125.     m.write(3, 'abc')
  126.     assert m.read(3, 3) == 'abc'
  127.     m.write(5, 'ab')
  128.     assert m.read(4, 3) == 'bab'
  129.     m.write(3, 'pqrstuvw')
  130.     assert m.read(3, 8) == 'pqrstuvw'
  131.     m.write(3, 'abcdef')
  132.     assert m.read(3, 7) == 'abcdefv'
  133.  
  134. def test_Storage_zero():
  135.     f = FakeOpen()
  136.     Storage([('a', 0)], f.open, f.exists, f.getsize)
  137.     assert f.files == {'a': []}
  138.  
  139. def test_resume_zero():
  140.     f = FakeOpen({'a': ''})
  141.     Storage([('a', 0)], f.open, f.exists, f.getsize)
  142.     assert f.files == {'a': []}
  143.  
  144. def test_Storage_with_zero():
  145.     f = FakeOpen()
  146.     m = Storage([('a', 3), ('b', 0), ('c', 3)], 
  147.         f.open, f.exists, f.getsize)
  148.     m.write(2, 'abc')
  149.     assert m.read(2, 3) == 'abc'
  150.     x = f.files.keys()
  151.     x.sort()
  152.     assert x == ['a', 'b', 'c']
  153.     assert len(f.files['a']) == 3
  154.     assert len(f.files['b']) == 0
  155.  
  156. def test_Storage_resume():
  157.     f = FakeOpen({'a': 'abc'})
  158.     m = Storage([('a', 4)], 
  159.         f.open, f.exists, f.getsize)
  160.     assert f.files.keys() == ['a']
  161.     assert m.read(0, 3) == 'abc'
  162.  
  163. def test_Storage_mixed_resume():
  164.     f = FakeOpen({'b': 'abc'})
  165.     m = Storage([('a', 3), ('b', 4)], 
  166.         f.open, f.exists, f.getsize)
  167.     x = f.files.keys()
  168.     x.sort()
  169.     assert x == ['a', 'b']
  170.     assert m.read(3, 3) == 'abc'
  171.